const crypto = require('crypto')
const fs = require('fs')
const request = require('request')


// *****************************************************************************************************
// API 地址
const apiUri = "https://api.weixin.qq.com"
// access_token（用于jssdk） GET
const addrAccessToken = apiUri + '/cgi-bin/token'
// jsapi_ticket GET
const addrJsapiTicket = apiUri + '/cgi-bin/ticket/getticket'
// access_token(用于获取用户信息) GET
const addrOauth2 = apiUri + '/sns/oauth2/access_token'
// 刷新access_token（此token为获取用户信息的token）GET
const addrRefreshToken = apiUri + '/sns/oauth2/refresh_token'
// 检验access_token是否有效 GET
const addrAuthToken = apiUri + '/sns/auth'
// 微信用户信息 GET
const addrUserinfo = apiUri + '/sns/userinfo'
// 微信菜单信息 GET
const addrMenuinfo = apiUri + '/cgi-bin/get_current_selfmenu_info'
// 设置微信菜单 POST
const addrSetMenu = apiUri + '/cgi-bin/menu/create'
// *****************************************************************************************************

const accessTokenJson = require('./access_token.json')
const jsapiTicketJson = require('./jsapi_ticket.json')

// 配置项
const wxConfig = require('./wx.config.json')
// 工具类
const WxUtil = require('./wx.util')

class WxApi {
	// 验证签名
	static checkSignature(signature, nonce, timestamp, token) {
		// 字典顺序拼接字符串
		let string = nonce + timestamp + token
		let sign = crypto.createHash('sha1').update(string).digest('hex')
		return sign === signature
	}

	// 获取access_token
	static getAccessToken() {
		return new Promise((resolve, reject)=> {
			//获取当前时间 (毫秒)
			let currentTime = new Date().getTime()
			//判断 本地存储的 access_token 是否有效
			if(accessTokenJson.access_token === "" || accessTokenJson.expires_time < currentTime){
				request.get({
					url: addrAccessToken, 
					qs: {
						grant_type: 'client_credential',
						appid: wxConfig.appid,
						secret: wxConfig.appsecret
					},
					json: true 
				},(error, res, body)=> {
			    	if(!error) {
						//更新本地存储的
			    		accessTokenJson.access_token = body.access_token
						accessTokenJson.expires_time = new Date().getTime() + (parseInt(body.expires_in) - 200) * 1000
						fs.writeFileSync(__dirname + '/access_token.json', JSON.stringify(accessTokenJson))
						//将获取后的 access_token 返回
						resolve(accessTokenJson.access_token)
			    	}else {
			    		reject(accessTokenJson.access_token)
			    	}
			    	
			    })
			}else{
			  //将本地存储的 access_token 返回
			  resolve(accessTokenJson.access_token)
			}
		});
	}

	// 根据code获取临时的access_token(与基本access_token不同)
	static oauth2(code) {
		// ?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
		return new Promise((resolve, reject)=> {
			request.get({
				url: addrOauth2, 
				qs: {
					appid: wxConfig.appid,
					secret: wxConfig.appsecret,
					code: code,
					grant_type: 'authorization_code'
				},
				json: true 
			},(error, res, body)=> {
				console.log('oauth2', body)
		    	if(!error) {
					// body
					// {
					//  "access_token":"ACCESS_TOKEN",
					// 	"expires_in":7200,
					// 	"refresh_token":"REFRESH_TOKEN",
					// 	"openid":"OPENID",
					// 	"scope":"SCOPE" 
					// }
					resolve(body)
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	}

	// 刷新临时的access_token
	static refreshToken(refreshToken) {
		// ?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
		return new Promise((resolve, reject)=> {
			request.get({
				url: addrRefreshToken, 
				qs: {
					appid: wxConfig.appid,
					grant_type: 'refresh_token',
					refresh_token: refreshToken
				},
				json: true 
			},(error, res, body)=> {
				console.log('refreshToken', body)
		    	if(!error) {
					// body
					// {
					//  "access_token":"ACCESS_TOKEN",
					// 	"expires_in":7200,
					// 	"refresh_token":"REFRESH_TOKEN",
					// 	"openid":"OPENID",
					// 	"scope":"SCOPE" 
					// }
					resolve(body)
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	}

	// 检测临时的access_token是否还有效
	static authToken(accessToken, openid) {
		// ?access_token=ACCESS_TOKEN&openid=OPENID
		return new Promise((resolve, reject)=> {
			request.get({
				url: addrAuthToken, 
				qs: {
					access_token: accessToken,
					openid: openid,
				},
				json: true 
			},(error, res, body)=> {
				console.log('authToken', body)
				// { "errcode":0,"errmsg":"ok"}
				// { "errcode":40003,"errmsg":"invalid openid"}
		    	if(!error) {
		    		if(body.errcode === 0) {
		    			resolve(true)
		    		}else {
		    			resolve(false)
		    		}
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	}

	// 获取微信用户信息 需要scope为 snsapi_userinfo（scope为获取access_token前的url中的一个参数）
	static getUserInfo(accessToken, openid) {
		// ?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
		return new Promise((resolve, reject)=> {
			request.get({
				url: addrUserinfo, 
				qs: {
					access_token: accessToken,
					openid: openid,
					lang: 'zh_CN',
				},
				json: true 
			},(error, res, body)=> {
				console.log(error, body)
		    	if(!error) {
					// body
					// {    "openid":" OPENID",
					// " nickname": NICKNAME,
					// "sex":"1",
					// "province":"PROVINCE"
					// "city":"CITY",
					// "country":"COUNTRY",
					// "headimgurl":    "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
					// "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
					// "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
					// }
					resolve(body)
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	}

	// 获取jsapi_ticket
	static getJsapiTicket(accessToken) {
		return new Promise((resolve, reject)=> {
			//获取当前时间 (毫秒)
			let currentTime = new Date().getTime()
			//判断 本地存储的 jsapi_ticket 是否有效
			if(jsapiTicketJson.jsapi_ticket === "" || jsapiTicketJson.expires_time < currentTime){
				request.get({
					url: addrJsapiTicket, 
					qs: {
						access_token: accessToken,
						type: 'jsapi',
					},
					json: true 
				},(error, res, body)=> {
			    	if(!error) {
						//更新本地存储的
						if(body.errcode === 0) {
							jsapiTicketJson.jsapi_ticket = body.ticket
							jsapiTicketJson.expires_time = new Date().getTime() + (parseInt(body.expires_in) - 200) * 1000
							fs.writeFileSync(__dirname + '/jsapi_ticket.json', JSON.stringify(jsapiTicketJson))
							//将获取后的 jsapi_ticket 返回
							resolve(jsapiTicketJson.jsapi_ticket)
						}else {
							reject(jsapiTicketJson.jsapi_ticket)
						}
			    	}else {
			    		reject(jsapiTicketJson.jsapi_ticket)
			    	}
			    	
			    })
			}else{
			  //将本地存储的 jsapi_ticket 返回
			  resolve(jsapiTicketJson.jsapi_ticket)
			}
		})
	}

	// 获取jssdk配置
	static getJsSdkConfig(ticket, url, jsApiList=[], debug=false) {
		const noncestr = WxUtil.getNonceStr()
		const timestamp = parseInt(new Date().getTime() / 1000, 10)

		const sign = WxUtil.makeJsapiSign({
			noncestr: noncestr,
			jsapi_ticket: ticket,
			timestamp: timestamp,
			url: url
		})
		return {
			debug: debug, // 开启调试模式,调用的所有api的返回值会在客户端alert出来，若要查看传入的参数，可以在pc端打开，参数信息会通过log打出，仅在pc端时才会打印。
		    appId: wxConfig.appid, // 必填，公众号的唯一标识
		    timestamp: timestamp, // 必填，生成签名的时间戳
		    nonceStr: noncestr, // 必填，生成签名的随机串
		    signature: sign,// 必填，签名
		    jsApiList: jsApiList 
		}
	}

	// 获取微信菜单(此accessToken为基本的accessToken)
	static getMenuinfo(accessToken) {
		// ?access_token=ACCESS_TOKEN
		return new Promise((resolve, reject)=> {
			request.get({
				url: addrMenuinfo, 
				qs: {
					access_token: accessToken,
				},
				json: true 
			},(error, res, body)=> {
				// console.log('menuinfo', JSON.stringify(body))
		    	if(!error) {
					resolve(body)
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	}

	// 设置微信菜单
	static setMenu(accessToken, data) {
		// ?access_token=ACCESS_TOKEN
		return new Promise((resolve, reject)=> {
			request.post({
				url: `${addrSetMenu}?access_token=${accessToken}`, 
				form: JSON.stringify(data), //必须是字符串,微信真是垃圾
				json: true 
			},(error, res, body)=> {
		    	if(!error) {
		    		// {"errcode":0,"errmsg":"ok"}
		    		// {"errcode":40018,"errmsg":"invalid button name size"}
		    		console.log('setMenu', body)
		    		if(body.errcode === 0) {
		    			resolve(true)
		    		}else {
		    			resolve(false)
		    		}
		    	}else {
		    		reject(error)
		    	}
		    })
		})
	} 
}

module.exports = WxApi